#region License, Terms and Conditions
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
#endregion
using System;
using System.Linq;
using Pesta.DataAccess.SqlServer;
using Pesta.Libraries.OAuth;

namespace raya.Library.OAuth
{
    public class RayaOAuthDataStore : IOAuthDataStore
    {
        public static readonly RayaOAuthDataStore Instance = new RayaOAuthDataStore();
        private RayaOAuthDataStore()
        {
        }

        public OAuthConsumer lookup_consumer(string consumerKey) 
        {

            using (var db = new LinqRayaDataContext())
            {
                var res = (from k in db.oauth_consumers
                           where k.consumer_key == consumerKey
                           select k).SingleOrDefault();

                if (res == null)
                {
                    return null;
                }

                return new OAuthConsumer(null, res.consumer_key, res.consumer_secret, null); 
            }
        }

        public OAuthToken lookup_token(OAuthConsumer consumer, string tokenType, string token) 
        {
            using (var db = new LinqRayaDataContext())
            {
                string consumerKey = consumer.consumerKey;
                var res = (from o in db.oauth_tokens
                           where o.type == tokenType && o.consumer_key == consumerKey && o.token_key == token
                           select o).SingleOrDefault();

                if (res == null)
                    throw new OAuthException("Unexpected token type (_token_type) or unknown token");

                return new OAuthToken(res.token_key, res.token_secret); 
            }
        }

        public string lookup_nonce(OAuthConsumer consumer, string token, string nonce, long timestamp) 
        {
            using (var db = new LinqRayaDataContext())
            {
                var res = (from p in db.oauth_nonces
                           where p.nonce_timestamp == timestamp
                           select p.nonce).SingleOrDefault();

                if (res == null)
                {
                    oauth_nonce non = new oauth_nonce { nonce = nonce, nonce_timestamp = timestamp };
                    db.oauth_nonces.InsertOnSubmit(non);
                    db.SubmitChanges();
                    return null;
                }

                return res; 
            }
        }

        public OAuthToken new_request_token(OAuthConsumer consumer)
        {
            using (var db = new LinqRayaDataContext())
            {
                string consumerKey = consumer.consumerKey;
                string consumerSecret = consumer.consumerSecret;
                var res = (from p in db.oauth_consumers
                           where p.consumer_key == consumerKey && p.consumer_secret == consumerSecret
                           select p.user_id);

                if (res.Count() == 0)
                    throw new OAuthException("Invalid consumer key (_consumer_key)");

                long userId = res.Single();
                OAuthToken _token = new OAuthToken(Guid.NewGuid().ToString(), OAuthUtil.md5(DateTime.UtcNow.ToString()));
                oauth_token token = new oauth_token
                                        {
                                            consumer_key = consumerKey,
                                            type = "request",
                                            token_key = _token.key,
                                            token_secret = _token.secret,
                                            user_id = userId
                                        };
                db.oauth_tokens.InsertOnSubmit(token);
                db.SubmitChanges();
                return _token; 
            }
        }

        public OAuthToken new_access_token(OAuthToken oauthToken, OAuthConsumer consumer) 
        {
            using (var db = new LinqRayaDataContext())
            {
                string tokenKey = oauthToken.key;
                var res = (from p in db.oauth_tokens
                           where p.type == "request" && p.token_key == tokenKey
                           select p).SingleOrDefault();
                if (res != null)
                {
                    if (res.authorized != 0)
                    {
                        OAuthToken token = new OAuthToken(Guid.NewGuid().ToString(), OAuthUtil.md5(DateTime.UtcNow.ToString()));
                        oauth_token ot = new oauth_token
                                             {
                                                 token_key = token.key,
                                                 type = "access",
                                                 token_secret = token.secret,
                                                 consumer_key = res.consumer_key,
                                                 user_id = res.user_id
                                             };
                        db.oauth_tokens.InsertOnSubmit(ot);
                        db.oauth_tokens.DeleteOnSubmit(res);
                        db.SubmitChanges();
                        return token;
                    }
                } 
            }
            return null;
        }

        public void authorize_request_token(string token, string userid) 
        {
            using (var db = new LinqRayaDataContext())
            {
                var result = (from t in db.oauth_tokens
                              where t.token_key == token
                              select t).SingleOrDefault();
                if (result != null)
                {
                    result.authorized = 1;
                    result.user_id = long.Parse(userid);
                    db.SubmitChanges();
                } 
            }
        }

        public long get_user_id(OAuthToken token) 
        {
            using (var db = new LinqRayaDataContext())
            {
                var res = from t in db.oauth_tokens
                          where t.token_key == token.key
                          select t.user_id;

                return res.SingleOrDefault(); 
            }
        }
    }
}